/*
*	File: Saver.cpp
*	Date: 12/13/2011
*	Author: Ivan Gao
*	Desc:
*/
#include "Saver.h"
bool SSaver::ExportSkeletonFile (const char * pFileName, SCoreSkeleton * pCoreSkeleton)
{
	ofstream file;
	file.open (pFileName, ios::out | ios::binary);
	if (!file)
	{
		return false;
	}
	if (!SBinaryFile::WriteBytes(file, SimpleAnimation::SKELETON_FILE_MAGIC, sizeof(SimpleAnimation::SKELETON_FILE_MAGIC)))
	{
		return false;
	} // if
	if (!SBinaryFile::WriteInteger(file, SimpleAnimation::SKELETON_FILE_VERSION))
	{
		return false;
	} // if

	// Write number of bones.
	if (!SBinaryFile::WriteInteger (file, pCoreSkeleton->GetNumCoreBones ()))
	{
		return false;
	} // if
	SVector3 sceneColor = pCoreSkeleton->GetSceneAmbientColor ();
	SBinaryFile::WriteFloat (file, sceneColor.x);
	SBinaryFile::WriteFloat (file, sceneColor.y);
	SBinaryFile::WriteFloat (file, sceneColor.z);
	int nBoneId = 0;
	SCoreBone * pCoreBone = NULL;
	for (; nBoneId < pCoreSkeleton->GetNumCoreBones (); ++ nBoneId)
	{
		pCoreBone = pCoreSkeleton->GetCoreBone (nBoneId);
		if (!SaveCoreBone (file, pCoreBone))
		{
			return false;
		}
	} // for
	file.close ();
	return true;
} // ExportSkeletonFile

bool SSaver::SaveCoreBone (ofstream & file, const SCoreBone * pCoreBone)
{
	// Write the name of the bone.
	if (!SBinaryFile::WriteString (file, pCoreBone->GetBoneName()))
	{
		return false;
	} // if

	// Write the translation of the bone.
	const SVector3 & translation = pCoreBone->GetTranslation();
	SBinaryFile::WriteFloat (file, translation.x);
	SBinaryFile::WriteFloat (file, translation.y);
	SBinaryFile::WriteFloat (file, translation.z);

	// Write the rotation of the bone.
	const SQuaternion & rotation = pCoreBone->GetRotation ();
	SBinaryFile::WriteFloat (file, rotation.x);
	SBinaryFile::WriteFloat (file, rotation.y);
	SBinaryFile::WriteFloat (file, rotation.z);
	SBinaryFile::WriteFloat (file, rotation.w);

	// Write the inverse of translation of world space.
	const SVector3 & translationBoneSpace = pCoreBone->GetTranslationBoneSpace ();
	SBinaryFile::WriteFloat (file, translationBoneSpace.x);
	SBinaryFile::WriteFloat (file, translationBoneSpace.y);
	SBinaryFile::WriteFloat (file, translationBoneSpace.z);

	// Write the inverse of the rotation of world space.
	const SQuaternion & rotationBoneSpace = pCoreBone->GetRotationBoneSpace();
	SBinaryFile::WriteFloat (file, rotationBoneSpace.x);
	SBinaryFile::WriteFloat (file, rotationBoneSpace.y);
	SBinaryFile::WriteFloat (file, rotationBoneSpace.z);
	SBinaryFile::WriteFloat (file, rotationBoneSpace.w);

	// Write the parent bone id.
	SBinaryFile::WriteInteger(file, pCoreBone->GetParentId());

	// Write the light data.
	SBinaryFile::WriteInteger(file, 0);
	SVector3 lightColor;
	SBinaryFile::WriteFloat (file, lightColor.x);
	SBinaryFile::WriteFloat (file, lightColor.y);
	SBinaryFile::WriteFloat (file, lightColor.z);

	// Get children list.
	const std::vector<int> & vecChildId = pCoreBone->GetChildVectorId();
	// Write the number of children.
	SBinaryFile::WriteInteger (file, (int)vecChildId.size ());
	// Write all children ids.
	std::vector<int>::iterator itr = const_cast<vector<int> &>(vecChildId).begin();
	while (itr != vecChildId.end ())
	{
		SBinaryFile::WriteInteger(file, *itr);
		++ itr;
	} // while

	return true;
} // if

bool SSaver::ExportCoreMaterialSet (const char * pFileName, const SCoreMaterialSet & rCoreMaterialSet)
{
	ofstream file;
	file.open(pFileName, ios::binary | ios::out);
	if (!file)
	{
		return false;
	} // if
	// Write the magic token
	if (!SBinaryFile::WriteBytes(file, SimpleAnimation::MATERIAL_FILE_MAGIC, sizeof(SimpleAnimation::MATERIAL_FILE_MAGIC)))
	{
		return false;
	}
	// Write the material file version
	SBinaryFile::WriteInteger(file, SimpleAnimation::MATERIAL_FILE_VERSION);
	// Write the number of materials
	int nCount = rCoreMaterialSet.GetSize();
	SBinaryFile::WriteInteger(file, nCount);
	// Write the all the materials info.
	for (int i = 0; i < nCount; ++i)
	{
		const SCoreMaterial * pCoreMaterial = rCoreMaterialSet.GetCoreMaterial(i);
		// Write the name of the material
		SBinaryFile::WriteString(file, pCoreMaterial->GetName().c_str());
		// The ambient color
		const SCoreMaterial::Color & ambientColor = pCoreMaterial->GetAmbientColor();
		char color[4];
		color[0] = ambientColor.red;
		color[1] = ambientColor.green;
		color[2] = ambientColor.blue;
		color[3] = ambientColor.alpha;
		SBinaryFile::WriteBytes(file, color, sizeof(color));
		// The diffuse color
		const SCoreMaterial::Color & diffuseColor = pCoreMaterial->GetDiffuseColor();
		color[0] = diffuseColor.red;
		color[1] = diffuseColor.green;
		color[2] = diffuseColor.blue;
		color[3] = diffuseColor.alpha;
		SBinaryFile::WriteBytes(file, color, sizeof(color));
		// The specular color.
		const SCoreMaterial::Color & specularColor = pCoreMaterial->GetSpecularColor();
		color[0] = specularColor.red;
		color[1] = specularColor.green;
		color[2] = specularColor.blue;
		color[3] = specularColor.alpha;
		SBinaryFile::WriteBytes(file, color, sizeof(color));
		// The specular shininess.
		SBinaryFile::WriteFloat (file, pCoreMaterial->GetShiness());
		// Number of maps
		int nMapCount = pCoreMaterial->GetMapCount();
		SBinaryFile::WriteInteger(file, nMapCount);
		// Write the each map info.
		for (int i = 0; i < nMapCount; ++i)
		{
			string fileName = pCoreMaterial->GetMapFileName(i);
			if (!fileName.empty())
			{
				string::size_type pos = fileName.find_last_of("\\/:");
				if (string::npos == pos)
				{
					SBinaryFile::WriteString(file, fileName.c_str());
				}
				else
				{
					SBinaryFile::WriteString(file, fileName.substr(pos+1).c_str());
				} // if
			}
		} // for
	} // for
	return true;
} // SaveCoreMaterialSet